package classfile

import "fmt"

type ClassFile struct {
	magic uint32
	minorVersion uint16
	majorVersion uint16
	constantPool ConstantPool
	accessFlags  uint16
	thisClass    uint16
	superClass   uint16
	interfaces   []uint16
	fields       []*MemberInfo
	methods      []*MemberInfo
	attributes   []AttributeInfo
}

// 字节解析成classFile结构体
func Parse(classDataByte []byte) (cf *ClassFile, err error) {
	defer func() {
		if r := recover(); r != nil {
			var ok bool
			err, ok = r.(error)
			if !ok {
				err = fmt.Errorf("%v", r)
			}
		}
	}()
	cr := &ClassReader{classDataByte}
	cf = &ClassFile{}
	cf.read(cr)
	return
}

func (self *ClassFile) read(reader *ClassReader) {
	// 解析魔数
	self.readAndCheckMagic(reader) // 见 3.2.3

	// 解析版本号
	self.readAndCheckVersion(reader) // 见 3.2.4

	// 解析常量池
	self.constantPool = readConstantPool(reader) // 见 3.3

	// 解析类访问标志
	self.accessFlags = reader.readUint16()

	// 解析类的常量池索引
	self.thisClass = reader.readUint16()

	// 解析父类的常量池索引
	self.superClass = reader.readUint16()

	// 解析接口的常量池索引
	self.interfaces = reader.readUint16s()

	// 解析字段及字段属性
	self.fields = readMembers(reader, self.constantPool) // 见 3.2.8

	// 解析方法及方法属性
	self.methods = readMembers(reader, self.constantPool)

	// 解析属性
	self.attributes = readAttributes(reader, self.constantPool) //见 3.4
}

// 校验class是否已CAFEBABE开头的魔数
func (self *ClassFile) readAndCheckMagic(reader *ClassReader) {
	magic := reader.readUint32()
	if magic != 0xCAFEBABE {
		panic("java.lang.ClassFormatError: magic错误，不是有效的class文件！")
	}
}
// 次版本号、主版本号
func (self *ClassFile) readAndCheckVersion(reader *ClassReader) {
	self.minorVersion = reader.readUint16()
	self.majorVersion = reader.readUint16()
	switch self.majorVersion {
		case 45:
			return
		case 46, 47, 48, 49, 50, 51, 52:
			if self.minorVersion == 0 {
				return
			}
	}
	panic("java.lang.UnsupportedClassVersionError!")
}

func (self *ClassFile) MajorVersion() uint16 {
	return self.majorVersion
}

func (self *ClassFile) ClassName() string {
	return self.constantPool.getClassName(self.thisClass)
}

func (self *ClassFile) SuperClassName() string {
	if self.superClass > 0 {
		return self.constantPool.getClassName(self.superClass)
	}
	return "" // 只有 java.lang.Object没有超类
}

func (self *ClassFile) InterfaceNames() []string {
	interfaceNames := make([]string, len(self.interfaces))
	for i, cpIndex := range self.interfaces {
		interfaceNames[i] = self.constantPool.getClassName(cpIndex)
	}
	return interfaceNames
}

func (self *ClassFile) MinorVersion() interface{} {
	return self.minorVersion
}
func (self *ClassFile) ConstantPool() ConstantPool {
	return self.constantPool
}
func (self *ClassFile) AccessFlags() interface{} {
	return self.accessFlags
}
func (self *ClassFile) Fields() []*MemberInfo {
	return self.fields
}
func (self *ClassFile) Methods() []*MemberInfo {
	return self.methods
}



